package com.maozzi.web.aop;

import cn.hutool.core.util.ObjectUtil;
import com.google.gson.Gson;
import com.maozzi.api.logger.LogService;
import com.maozzi.api.logger.annotation.SysLogger;
import com.maozzi.api.logger.model.LoggerDTO;
import com.maozzi.common.enums.BizCodeEnum;
import com.maozzi.common.exception.BizException;
import com.maozzi.common.model.ResultVO;
import com.maozzi.web.auth.model.UserInfo;
import com.maozzi.web.auth.util.SsoUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 操作记录 切面
 *
 * @author maozi
 */
@Aspect
@Component
public class SysLoggerAspect {

    private final static Gson GSON = new Gson();

    @Resource
    @Lazy
    private LogService loggerService;

    @Pointcut("@annotation(com.maozzi.api.logger.annotation.SysLogger)")
    public void controllerAspect() {
    }

    @Around("controllerAspect()")
    public Object around(ProceedingJoinPoint joinPoint) {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String ip = request.getRemoteAddr();

        // 获取 SysLogger 注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String message = "";
        SysLogger annotation = method.getAnnotation(SysLogger.class);
        if (ObjectUtil.isNotEmpty(annotation)) {
            message = annotation.message();
        }

        // 当前登录用户
        String username = "";
        UserInfo userInfo = SsoUtil.get();
        if (Objects.nonNull(userInfo)) {
            username = userInfo.getName();
        }

        // 继续执行业务
        Object[] arguments = joinPoint.getArgs();
        Object res;
        try {
            res = joinPoint.proceed(arguments);

            // 保存日志
            this.addLog(ip, username, message, GSON.toJson(arguments), GSON.toJson(res));
        } catch (Throwable e) {
            if (e instanceof BizException bizException) {
                res = ResultVO.fail(bizException.getCode(), e.getMessage());
                // 保存日志
                this.addLog(ip, username, message, GSON.toJson(arguments), GSON.toJson(res));

                throw bizException;
            } else {
                res = ResultVO.fail(e.getMessage());
                // 保存日志
                this.addLog(ip, username, message, GSON.toJson(arguments), GSON.toJson(res));

                throw new BizException(BizCodeEnum.SERVER_ERROR, e.getMessage());
            }
        }

        // 返回运行结果
        return res;
    }

    /**
     * 保存日志
     *
     * @param ip       ip
     * @param username 当前用户名
     * @param message  日志描述
     * @param arg      参数
     * @param res      返回值
     */
    private void addLog(String ip, String username, String message, Object arg, Object res) {
        LoggerDTO dto = new LoggerDTO(ip, username, message, GSON.toJson(arg), GSON.toJson(res));

        loggerService.addLog(dto);
    }
}
